﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace MugenInjection.Interface
{
    /// <summary>
    /// Provides a path to resolve instances.
    /// </summary>
    public interface IInjectorResolver : IServiceProvider
    {
        /// <summary>
        /// Creates the <see cref="IBindingContext"/> for the current <see cref="IInjectorResolver"/>.
        /// </summary>
        /// <param name="service">The specifed service <see cref="Type"/>.</param>
        /// <param name="member">The specified <see cref="MemberInfo"/> when injected specified service. Can be null.</param>
        /// <param name="parameterInfo">The specified <see cref="ParameterInfo"/> when injected specified service.</param>
        /// <param name="parameters">The specified parameters for service.</param>
        /// <param name="specialParameters">The special parameters for resolve specified service.</param>
        /// <returns>An instance of <see cref="IBindingContext"/>.</returns>
        IBindingContext CreateContext(Type service, MemberInfo member, ParameterInfo parameterInfo,
                                      IEnumerable<IInjectionParameter> parameters,
                                      IDictionary<string, object> specialParameters);

        /// <summary>
        /// Injects values into properties, fields, methods in the specified object.
        /// </summary>
        /// <param name="target">The specified target for inject.</param>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        void Inject<T>(ref T target, IBindingContext bindingContext);

        /// <summary>
        /// Determines whether the specified request can be resolved.
        /// </summary>
        /// <param name="bindingContext"> The specified <see cref="IBindingContext"/>.</param>
        /// <param name="searchInParent">If set to <c>true</c> search in parent bindings.</param>
        /// <param name="includeImplicitBindings">If set to <c>false</c> implicit bindings are ignored.</param>
        /// <returns><c>True</c> if the specified service has been resolved; otherwise, <c>false</c>.</returns>
        bool CanResolve(IBindingContext bindingContext, bool searchInParent, bool includeImplicitBindings);

        /// <summary>
        /// Resolves an instance for the specified <see cref="IBindingContext"/>.
        /// </summary>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        /// <returns>An instance of the service.</returns>
        object Resolve(IBindingContext bindingContext);

        /// <summary>
        /// Resolves all instances for the specified <see cref="IBindingContext"/>.
        /// </summary>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        /// <param name="useParentToResolve">If <c>true</c> also use parent bindings to resolve.</param>
        /// <returns>A series of instances of the service.</returns>
        IList<object> ResolveAll(IBindingContext bindingContext, bool useParentToResolve);

        /// <summary>
        /// Resolves all instances for the specified service <see cref="Type"/>.
        /// </summary>
        /// <param name="service">Service for resolve.</param>
        /// <param name="parameters">Parameters for service.</param>
        /// <param name="specialParameters">Special parameters for resolve specified service.</param>
        /// <param name="useParentToResolve">If <c>true</c> also use parent bindings to resolve.</param>
        /// <returns>A series of instances of the service.</returns>
        IList<object> ResolveAll(Type service, IEnumerable<IInjectionParameter> parameters,
                                 IDictionary<string, object> specialParameters, bool useParentToResolve);
    }
}